///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __TextureUnitState_H__
#define __TextureUnitState_H__

#include "OgrePrerequisites.h"
#include "OgreCommon.h"
#include "OgreBlendMode.h"
#include "math/matrix4.h "
#include "OgreIteratorWrappers.h"
#include "OgreString.h"
#include "OgreTexture.h"

namespace Ogre {
	
	
	
	class _OgreExport TextureUnitState : public MemAlloc_Resource
    {
        friend class RenderSystem;
    public:
        
        enum TextureEffectType
        {
            /// Generate all texture coords based on angle between camera and vertex
            ET_ENVIRONMENT_MAP,
            /// Generate texture coords based on a frustum
            ET_PROJECTIVE_TEXTURE,
            /// Constant u/v scrolling effect
            ET_UVSCROLL,
			/// Constant u scrolling effect
            ET_USCROLL,
			/// Constant u/v scrolling effect
            ET_VSCROLL,
            /// Constant rotation
            ET_ROTATE,
            /// More complex transform
            ET_TRANSFORM

        };

        
        enum EnvMapType
        {
            /// Envmap based on vector from camera to vertex position, good for planar geometry
            ENV_PLANAR,
            /// Envmap based on dot of vector from camera to vertex and vertex normal, good for curves
            ENV_CURVED,
            /// Envmap intended to supply reflection vectors for cube mapping
            ENV_REFLECTION,
            /// Envmap intended to supply normal vectors for cube mapping
            ENV_NORMAL
        };

        
        enum TextureTransformType
        {
            TT_TRANSLATE_U,
            TT_TRANSLATE_V,
            TT_SCALE_U,
            TT_SCALE_V,
            TT_ROTATE
        };

        
        enum TextureAddressingMode
        {
            /// Texture wraps at values over 1.0
            TAM_WRAP,
            /// Texture mirrors (flips) at joins over 1.0
            TAM_MIRROR,
            /// Texture clamps at 1.0
            TAM_CLAMP,
            /// Texture coordinates outside the range [0.0, 1.0] are set to the border colour
            TAM_BORDER
        };

		
		struct UVWAddressingMode
		{
			TextureAddressingMode u, v, w;
		};

        
        enum TextureCubeFace
        {
            CUBE_FRONT = 0,
            CUBE_BACK = 1,
            CUBE_LEFT = 2,
            CUBE_RIGHT = 3,
            CUBE_UP = 4,
            CUBE_DOWN = 5
        };

        
        struct TextureEffect {
            TextureEffectType type;
            int subtype;
            Real arg1, arg2;
            WaveformType waveType;
            Real base;
            Real frequency;
            Real phase;
            Real amplitude;
            Controller<Real>* controller;
            const Frustum* frustum;
        };

        
        typedef multimap<TextureEffectType, TextureEffect>::type EffectMap;

        
        TextureUnitState(Pass* parent);

        TextureUnitState(Pass* parent, const TextureUnitState& oth );

        TextureUnitState & operator = ( const TextureUnitState& oth );

        
        ~TextureUnitState();

        
		TextureUnitState( Pass* parent, const String& texName, unsigned int texCoordSet = 0);

        
        const String& getTextureName(void) const;

        
        void setTextureName( const String& name, TextureType ttype = TEX_TYPE_2D);

        
        void setTexture( const TexturePtr& texPtr);

		
        void setCubicTextureName( const String& name, bool forUVW = false );

        
        void setCubicTextureName( const String* const names, bool forUVW = false );

        
        void setCubicTexture( const TexturePtr* const texPtrs, bool forUVW = false );

		
        void setAnimatedTextureName( const String& name, unsigned int numFrames, Real duration = 0 );

        
        void setAnimatedTextureName( const String* const names, unsigned int numFrames, Real duration = 0 );

        
        std::pair< size_t, size_t > getTextureDimensions( unsigned int frame = 0 ) const;

        
        void setCurrentFrame( unsigned int frameNumber );

        
        unsigned int getCurrentFrame(void) const;

        
        const String& getFrameTextureName(unsigned int frameNumber) const;

        
        void setFrameTextureName(const String& name, unsigned int frameNumber);

        
        void addFrameTextureName(const String& name);
        
        void deleteFrameTextureName(const size_t frameNumber);
        
        unsigned int getNumFrames(void) const;


		
		enum BindingType
		{
			
			BT_FRAGMENT = 0,
			
			BT_VERTEX = 1
		};
		
		enum ContentType
		{
			/// Normal texture identified by name
			CONTENT_NAMED = 0,
			/// A shadow texture, automatically bound by engine
			CONTENT_SHADOW = 1,
			/// A compositor texture, automatically linked to active viewport's chain
			CONTENT_COMPOSITOR = 2
		};

		
		void setBindingType(BindingType bt);

		
		BindingType getBindingType(void) const;

		
		void setContentType(ContentType ct);
		
		ContentType getContentType(void) const;

        
        bool isCubic(void) const;

        
        bool is3D(void) const;

        
        TextureType getTextureType(void) const;

        
        void setDesiredFormat(PixelFormat desiredFormat);

        
        PixelFormat getDesiredFormat(void) const;

        
        void setNumMipmaps(int numMipmaps);

        
        int getNumMipmaps(void) const;

		
        void setIsAlpha(bool isAlpha);

		
        bool getIsAlpha(void) const;

		/// @copydoc Texture::setHardwareGammaEnabled
		void setHardwareGammaEnabled(bool enabled);
		/// @copydoc Texture::isHardwareGammaEnabled
		bool isHardwareGammaEnabled() const;

        
        unsigned int getTextureCoordSet(void) const;

        
        void setTextureCoordSet(unsigned int set);

        
        void setTextureTransform(const Matrix4& xform);

        
        const Matrix4& getTextureTransform(void) const;

        
        void setTextureScroll(Real u, Real v);

        
        void setTextureUScroll(Real value);
        // get texture uscroll value
        Real getTextureUScroll(void) const;

        
        void setTextureVScroll(Real value);
        // get texture vscroll value
        Real getTextureVScroll(void) const;

        
        void setTextureUScale(Real value);
        // get texture uscale value
        Real getTextureUScale(void) const;

        
        void setTextureVScale(Real value);
        // get texture vscale value
        Real getTextureVScale(void) const;

        
        void setTextureScale(Real uScale, Real vScale);

        
        void setTextureRotate(const Radian& angle);
        // get texture rotation effects angle value
        const Radian& getTextureRotate(void) const;

        
        const UVWAddressingMode& getTextureAddressingMode(void) const;

        
        void setTextureAddressingMode( TextureAddressingMode tam);

        
        void setTextureAddressingMode( TextureAddressingMode u, 
			TextureAddressingMode v, TextureAddressingMode w);

        
        void setTextureAddressingMode( const UVWAddressingMode& uvw);

        
        void setTextureBorderColour(const ColourValue& colour);

        
        const ColourValue& getTextureBorderColour(void) const;

		
        void setColourOperationEx(
            LayerBlendOperationEx op,
            LayerBlendSource source1 = LBS_TEXTURE,
            LayerBlendSource source2 = LBS_CURRENT,

            const ColourValue& arg1 = ColourValue::White,
            const ColourValue& arg2 = ColourValue::White,

            Real manualBlend = 0.0);

        
        void setColourOperation( const LayerBlendOperation op);

        
        void setColourOpMultipassFallback( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor);

        
        const LayerBlendModeEx& getColourBlendMode(void) const;

        
        const LayerBlendModeEx& getAlphaBlendMode(void) const;

        
        SceneBlendFactor getColourBlendFallbackSrc(void) const;

        
        SceneBlendFactor getColourBlendFallbackDest(void) const;

        
        void setAlphaOperation(LayerBlendOperationEx op,
            LayerBlendSource source1 = LBS_TEXTURE,
            LayerBlendSource source2 = LBS_CURRENT,
            Real arg1 = 1.0,
            Real arg2 = 1.0,
            Real manualBlend = 0.0);

        
        void addEffect(TextureEffect& effect);

        
        void setEnvironmentMap(bool enable, EnvMapType envMapType = ENV_CURVED);

        
        void setScrollAnimation(Real uSpeed, Real vSpeed);

        
        void setRotateAnimation(Real speed);

        
        void setTransformAnimation( const TextureTransformType ttype,
            const WaveformType waveType, Real base = 0, Real frequency = 1, Real phase = 0, Real amplitude = 1 );


        
        void setProjectiveTexturing(bool enabled, const Frustum* projectionSettings = 0);

        
        void removeAllEffects(void);

        
        void removeEffect( const TextureEffectType type );

        
        bool isBlank(void) const;

        
        void setBlank(void);

		
		bool isTextureLoadFailing() const { return mTextureLoadFailed; }

		
		void retryTextureLoad() { mTextureLoadFailed = false; }

        // get texture effects in a multimap paired array
        const EffectMap& getEffects(void) const;
        // get the animated-texture animation duration
        Real getAnimationDuration(void) const;

        
        void setTextureFiltering(TextureFilterOptions filterType);
        
        void setTextureFiltering(FilterType ftype, FilterOptions opts);
        
        void setTextureFiltering(FilterOptions minFilter, FilterOptions magFilter, FilterOptions mipFilter);
        // get the texture filtering for the given type
        FilterOptions getTextureFiltering(FilterType ftpye) const;

        
        void setTextureAnisotropy(unsigned int maxAniso);
        // get this layer texture anisotropy level
        unsigned int getTextureAnisotropy() const;

		
		void setTextureMipmapBias(float bias) { mMipmapBias = bias; }
		
		float getTextureMipmapBias(void) const { return mMipmapBias; }

		
		void setCompositorReference(const String& compositorName, const String& textureName, size_t mrtIndex = 0);

		
		const String& getReferencedCompositorName() const { return mCompositorRefName; }
		
		const String& getReferencedTextureName() const { return mCompositorRefTexName; }
		 
		size_t getReferencedMRTIndex() const { return mCompositorRefMrtIndex; }
	
        /// Gets the parent Pass object
        Pass* getParent(void) const { return mParent; }

		
		void _prepare(void);
		
		void _unprepare(void);
		
		void _load(void);
		
		void _unload(void);
        /// Returns whether this unit has texture coordinate generation that depends on the camera
        bool hasViewRelativeTextureCoordinateGeneration(void) const;

        // Is this loaded?
        bool isLoaded(void) const;
        
        void _notifyNeedsRecompile(void);

        
        void setName(const String& name);
        /// get the name of the Texture Unit State
        const String& getName(void) const { return mName; }

        
        void setTextureNameAlias(const String& name);
        
        const String& getTextureNameAlias(void) const { return mTextureNameAlias;}

        
        bool applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply = true);

		
		void _notifyParent(Pass* parent);

		
		const TexturePtr& _getTexturePtr(void) const;
		
		const TexturePtr& _getTexturePtr(size_t frame) const;
	
		
		void _setTexturePtr(const TexturePtr& texptr);
		
		void _setTexturePtr(const TexturePtr& texptr, size_t frame);

		
		Controller<Real>* _getAnimController() const { return mAnimController; }
protected:
        // State
        /// The current animation frame.
        unsigned int mCurrentFrame;

        /// Duration of animation in seconds
        Real mAnimDuration;            
        bool mCubic; // is this a series of 6 2D textures to make up a cube?
		
        TextureType mTextureType; 
        PixelFormat mDesiredFormat;
		int mTextureSrcMipmaps; // Request number of mipmaps

        unsigned int mTextureCoordSetIndex;
        UVWAddressingMode mAddressMode;
        ColourValue mBorderColour;

        LayerBlendModeEx mColourBlendMode;
        SceneBlendFactor mColourBlendFallbackSrc;
        SceneBlendFactor mColourBlendFallbackDest;

        LayerBlendModeEx mAlphaBlendMode;
        mutable bool mTextureLoadFailed;
        bool mIsAlpha;
		bool mHwGamma;

        mutable bool mRecalcTexMatrix;
        Real mUMod, mVMod;
        Real mUScale, mVScale;
        Radian mRotate;
        mutable Matrix4 mTexModMatrix;

        /// Texture filtering - minification
        FilterOptions mMinFilter;
        /// Texture filtering - magnification
        FilterOptions mMagFilter;
        /// Texture filtering - mipmapping
        FilterOptions mMipFilter;
        ///Texture anisotropy
        unsigned int mMaxAniso;
		/// Mipmap bias (always float, not Real)
		float mMipmapBias;

        bool mIsDefaultAniso;
        bool mIsDefaultFiltering;
		/// Binding type (fragment or vertex pipeline)
		BindingType mBindingType;
		/// Content type of texture (normal loaded texture, auto-texture)
		ContentType mContentType;
		/// The index of the referenced texture if referencing an MRT in a compositor
		size_t mCompositorRefMrtIndex;

        //-----------------------------------------------------------------------------
        // Complex members (those that can't be copied using memcpy) are at the end to 
        // allow for fast copying of the basic members.
        //
        vector<String>::type mFrames;
		mutable vector<TexturePtr>::type mFramePtrs;
        String mName;               // optional name for the TUS
        String mTextureNameAlias;       // optional alias for texture frames
        EffectMap mEffects;
		///The data that references the compositor
		String mCompositorRefName;
		String mCompositorRefTexName;
        //-----------------------------------------------------------------------------

        //-----------------------------------------------------------------------------
        // Pointer members (those that can't be copied using memcpy), and MUST
        // preserving even if assign from others
        //
        Pass* mParent;
        Controller<Real>* mAnimController;
        //-----------------------------------------------------------------------------


        
        void recalcTextureMatrix(void) const;

        
        void createAnimController(void);

        
        void createEffectController(TextureEffect& effect);

		
		void ensurePrepared(size_t frame) const;
		
		void ensureLoaded(size_t frame) const;


    };

	
	

}

#endif
